/* The custom memory chart widget */

#ifndef MC_MEMORY_CHART_HPP
#define MC_MEMORY_CHART_HPP

#include <sigc++/sigc++.h>

#include <glibmm/refptr.h>
#include <glibmm/ustring.h>

#include <gdkmm/pixbuf.h>

#include <cairomm/context.h>
#include <cairomm/refptr.h>

#include <gtkmm/label.h>
#include <gtkmm/layout.h>
#include <gtkmm/liststore.h>

#include <memchart/class_info.hpp>
#include <memchart/types.hpp>

#include "chart_box.hpp"
#include "object_map.hpp"

namespace memchart
{
	class MemoryChart : public Gtk::Layout
	{
		public:

			MemoryChart ();

			Glib::RefPtr<Gdk::Pixbuf> get_pixbuf ();

			enum LayoutAlgorithm
			{
				LAYOUT_NONE,
				LAYOUT_TREE,
				LAYOUT_LIST,
				LAYOUT_DAG,
				LAYOUT_GENERIC
			};
			
			/* Render a new picture based on @objects */
			void update (const object_map & objects, LayoutAlgorithm advice);

			struct LayoutListColumns : public Gtk::TreeModelColumnRecord
			{
				LayoutListColumns ()
				{
					add(id);
					add(name);
				}
				
				Gtk::TreeModelColumn<LayoutAlgorithm> id;
				Gtk::TreeModelColumn<Glib::ustring> name;
			};

			sigc::signal<void, const Glib::ustring &> signal_status_message;
			LayoutListColumns layout_list_columns;
			Glib::RefPtr<Gtk::ListStore> layout_list_model;

		private:

			static const int hspacing = 30, vspacing = 30;

			bool               need_update;

			LayoutAlgorithm    layout_algorithm;

			box_map            boxes;
			bool               is_dag, is_tree, is_list;
			vector<box_iter>   torder; /* Topological order of vertices */
			box_iter           list_head;

			void analyze_graph ();

			/* Add or delete chart boxes from object map */
			void update_boxes (const object_map & objects);

			/* Update arrows */
			void draw_arrows (Cairo::RefPtr<Cairo::Context> & cr);

			bool on_expose_event (GdkEventExpose *event);
			bool on_value_change (GdkEventButton *event,
				const member_info *m, uintptr_t obj, Gtk::Label *label);

			/* Layout functions */
			void layout_list ();
			void layout_tree ();
			void layout_dag ();
			void layout_generic ();

			/* Helper functions */
			void make_boxes_unseen();
			size_t traverse_list (box_iter & v);
			pair<int, int> tree_align (chart_box & box, int left, int top);
	};
}

#endif /* MC_MEMORY_CHART_HPP */
